package com.tools.middle.redis.client;

import com.tools.common.exception.DataGenerationException;
import com.tools.common.object.Note;
import com.tools.middle.redis.RedisKit;
import com.tools.middle.redis.RedisSource;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;

import java.util.LinkedHashSet;

/**
 * 自定义包装的 JedisCluster 集群操作客户端实例
 * 需要在 Redis 自己的 redis.conf 文件下开启集群设置
 * 大约在 647 行左右，将 【cluster-enabled】 改为 yes，并去掉最前面的注释符【#】
 * 另外集群不要只开一个节点，否则还是可能启动不了
 * */
@Note("自定义包装的 JedisCluster 集群操作客户端实例。" +
        "需要在 Redis 自己的 redis.conf 文件下开启集群设置。" +
        "大约在 647 行左右，将 【cluster-enabled】 改为 yes，并去掉最前面的注释符【#】。" +
        "另外集群不要只开一个节点，否则还是可能启动不了")
public final class JedisClusterPlus extends AbsJedisCluster {

    @Note("Jedis 集群客户端实例。" +
            "在 3.0.0 以后的版本 JedisCluster 已经是线程安全的了，可以用于单例操作")
    private final JedisCluster jedisCluster;

    /* *******************************************************************************************
     *
     *          构造器
     *
     * *******************************************************************************************
     * */

    public JedisClusterPlus(RedisSource source) {
        this.jedisCluster = private_initClusterClientByProfileConfig(source);
    }

    public JedisClusterPlus(GenericObjectPoolConfig<Jedis> config, LinkedHashSet<HostAndPort> nodes) {
        this.jedisCluster = new JedisCluster(nodes, config);
    }

    /* *******************************************************************************************
     *
     *          操作方法
     *
     * *******************************************************************************************
     * */

    @Note("获取 Jedis 集群客户端实例")
    @Override
    public JedisCluster jedisCluster() {
        return jedisCluster;
    }

    @Note("关闭集群节点的客户端")
    @Override
    public void close() {
        jedisCluster.close();
    }


    /* *******************************************************************************************
     *
     *          操作方法
     *
     * *******************************************************************************************
     * */

    @Note("从外部配置文件中读取配置项，然后根据读取到的配置项初始化内部 JedisCluster 集群客户端操作实例")
    private JedisCluster private_initClusterClientByProfileConfig(RedisSource source) {
        if(source == null) throw new NullPointerException("Redis 配置项包装实体为 null，无法根据配置项构建 Jedis 连接池");
        Logger logger = LoggerFactory.getLogger(JedisClusterPlus.class);
        logger.info("正在尝试扫描 Redis 配置项并封装实例...");
        LinkedHashSet<HostAndPort> hostAndPortSet = source.getHostAndPortSet();
        if(hostAndPortSet != null && !hostAndPortSet.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            for (HostAndPort n : hostAndPortSet) {
                builder.append('\n').append(n.toString());
            }
            logger.info("扫描到 Redis 集群节点: {}\n正在配置集群客户端实例...", builder);
            return RedisKit.newJedisCluster(source);
        }
        String err = "没有扫描到 Redis 节点，请至少配置 1 个以上的 Redis 节点: 【节点ip:节点端口】";
        logger.error(err);
        throw new DataGenerationException(err);
    }
}
